//
// This file is part of the aMule Project.
//
// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
// Copyright (c) 2002-2011 Timo Kujala ( tiku@users.sourceforge.net )
//
// Any parts of this program derived from the xMule, lMule or eMule project,
// or contributed by third-party developers are copyrighted by their
// respective authors.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
//


#include <wx/wfstream.h>
#include <wx/protocol/http.h>


#include "HTTPDownload.h"				// Interface declarations
#include <wx/filename.h>				// Needed for wxFileName
#include <view/InputDialog.h>


typedef wxGauge wxGaugeControl;

DECLARE_LOCAL_EVENT_TYPE(wxEVT_HTTP_PROGRESS, wxANY_ID)
DECLARE_LOCAL_EVENT_TYPE(wxEVT_HTTP_SHUTDOWN, wxANY_ID)

#ifndef wxGA_PROGRESSBAR
#define wxGA_PROGRESSBAR 0
#endif
#define CastChild( IdOrName, type )			dynamic_cast<type*>( FindWindow( IdOrName ) )

enum{
    ID_ANIMATE,
    ID_HTTP_DOWNLOAD_PROGRESS,
    IDC_DOWNLOAD_SIZE,
    ID_HTTP_CANCEL
};
//typedef wxGauge wxGaugeControl;
/*
 * wxSizer *downloadDlg( wxWindow *parent, bool call_fit = TRUE, bool set_sizer = TRUE );
 */
wxSizer *downloadDlg( wxWindow *parent, bool call_fit, bool set_sizer )
{
    auto *item0 = new wxBoxSizer( wxVERTICAL );

    //put the gif
    //MuleGifCtrl *item1 = new MuleGifCtrl(parent,ID_ANIMATE,wxPoint(0,0),wxSize(272,60),wxNO_BORDER);
    //wxASSERT( item1 );
    //item0->Add( item1, 0, wxFIXED_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );

    auto *item2 = new wxStaticText( parent, -1, _("Downloading, please wait ..."), wxDefaultPosition, wxDefaultSize, 0 );
    item0->Add( item2, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );

    auto *item3 = new wxGauge( parent, ID_HTTP_DOWNLOAD_PROGRESS, 100, wxDefaultPosition, wxSize(-1,10), wxGA_SMOOTH|wxGA_PROGRESSBAR );
    item0->Add( item3, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );

    auto *item4 = new wxStaticText( parent, IDC_DOWNLOAD_SIZE, _("Unknown size"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE );
    item0->Add( item4, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );

    auto *item5 = new wxStaticLine( parent, -1, wxDefaultPosition, wxSize(20,-1), wxLI_HORIZONTAL );
    item0->Add( item5, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );

    auto *item6 = new wxButton( parent, ID_HTTP_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
    item6->SetDefault();
    item0->Add( item6, 0, wxALIGN_CENTER|wxALL, 5 );

    if (set_sizer)
    {
        parent->SetSizer( item0 );
        if (call_fit)
            item0->SetSizeHints( parent );
    }

    return item0;
}

/*
 * action驱动
 * call by the main_frame
 * main_frame then call the request file
 * event source
 * create the dialog
 * wxEvent evt;
 * bind(...)
 * dialog::onPercent
 *
 * main frame create thread
 * action
 * post event to the dialog
 */
class CHTTPDownloadDialog : public wxDialog
{
public:
	explicit CHTTPDownloadDialog(CHTTPDownloadThread* thread)
	  : wxDialog(wxTheApp->GetTopWindow(), -1, _("Downloading..."),
			wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxSYSTEM_MENU)
	{
	    //have a progress
		downloadDlg(this, true, TRUE )->Show(this, true);

		/*
		m_progressbar = CastChild(ID_HTTP_DOWNLOAD_PROGRESS, wxGaugeControl);
		m_progressbar->SetRange(100);
        */
		/*
		m_ani = CastChild(ID_ANIMATE, MuleGifCtrl);
		m_ani->LoadData((const char*)inetDownload, sizeof(inetDownload));
		m_ani->Start();
        */
		m_thread = thread;
	}

	~CHTTPDownloadDialog() override {
		StopThread();
	}

	void UpdateGauge(int total, int current) {

	    wxString temp;
	    temp.sprintf( wxT("( %s / %s )"), total , current );
        //wxStaticText *p;
		CastChild(IDC_DOWNLOAD_SIZE, wxStaticText)->SetLabel( temp );

		if (total && (total != m_progressbar->GetRange())) {
			m_progressbar->SetRange(total);
		}

		if (current && (current <= total)) {
			m_progressbar->SetValue(current);
		}

		Layout();
	}

private:
	void StopThread() {
	    /*
		if (m_thread) {
			m_thread->Stop();
			delete m_thread;
			m_thread = nullptr;
		}*/
	}

	void OnBtnCancel(wxCommandEvent& WXUNUSED(evt)) {
		//AddLogLineN(_("HTTP download cancelled"));
		Show(false);
		StopThread();
	}

	/*
	void OnProgress(CMuleInternalEvent& evt) {
		UpdateGauge(evt.GetExtraLong(), evt.GetInt());
	}

	void OnShutdown(CMuleInternalEvent& WXUNUSED(evt)) {
		Show(false);
		Destroy();
	}
    */
	wxThread*	m_thread;
	//MuleGifCtrl*	m_ani;
	wxGaugeControl* m_progressbar;

	DECLARE_EVENT_TABLE()
};


BEGIN_EVENT_TABLE(CHTTPDownloadDialog, wxDialog)
	EVT_BUTTON(ID_HTTP_CANCEL, CHTTPDownloadDialog::OnBtnCancel)
	//EVT_MULE_INTERNAL(wxEVT_HTTP_PROGRESS, -1, CHTTPDownloadDialog::OnProgress)
	//EVT_MULE_INTERNAL(wxEVT_HTTP_SHUTDOWN, -1, CHTTPDownloadDialog::OnShutdown)
END_EVENT_TABLE()

DEFINE_LOCAL_EVENT_TYPE(wxEVT_HTTP_PROGRESS)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_HTTP_SHUTDOWN)

//#endif

/*
 * thread and action
 * dialog
 * service Thread: ignore
 * wxTHREAD_JOINABLE : wxTHREAD_DETACHED
 * work thread
 */
CHTTPDownloadThread::CHTTPDownloadThread(const wxString& url, const wxString& save_path )
        : wxThread( wxTHREAD_JOINABLE ),
      m_url(url),
      m_temp_file(save_path),
      m_result(-1),
      m_companion(nullptr)
{
    auto* dialog = new CHTTPDownloadDialog(this);
    dialog->Show(true);
    m_companion = dialog;

	// Get the date on which the original file was last modified
	// Only if it's the same URL we used for the last download and if the file exists.

    wxFileName origFile = wxFileName(wxT(""));
    if (origFile.FileExists()) {
        //AddDebugLogLineN(logHTTP, CFormat(wxT("URL %s matches and file %s exists, only download if newer")) % url % oldFilename);
        m_last_modified = origFile.GetModificationTime();
    }

	wxMutexLocker lock(s_allThreadsMutex);
	s_allThreads.insert(this);
}


// Format the given date to a RFC-2616 compliant HTTP date
// Example: Thu, 14 Jan 2010 15:40:23 GMT
wxString CHTTPDownloadThread::FormatDateHTTP(const wxDateTime& date)
{
	static const wxChar* s_months[] = { wxT("Jan"), wxT("Feb"), wxT("Mar"), wxT("Apr"),
                                     wxT("May"), wxT("Jun"), wxT("Jul"), wxT("Aug"),
                                     wxT("Sep"), wxT("Oct"), wxT("Nov"), wxT("Dec") };
	static const wxChar* s_dow[] = { wxT("Sun"), wxT("Mon"), wxT("Tue"), wxT("Wed"),
                                  wxT("Thu"), wxT("Fri"), wxT("Sat") };
    /*
	return CFormat(wxT("%s, %02d %s %d %02d:%02d:%02d GMT"))
	    % s_dow[date.GetWeekDay(wxDateTime::UTC)]
	    % date.GetDay(wxDateTime::UTC)
	    % s_months[date.GetMonth(wxDateTime::UTC)]
	    % date.GetYear(wxDateTime::UTC) % date.GetHour(wxDateTime::UTC) % date.GetMinute(wxDateTime::UTC) % date.GetSecond(wxDateTime::UTC);*/
    wxString temp;
    temp.sprintf( wxT("%s, %02d %s %d %02d:%02d:%02d GMT")),
     s_dow[date.GetWeekDay(wxDateTime::UTC)],
     date.GetDay(wxDateTime::UTC),
     s_months[date.GetMonth(wxDateTime::UTC)],
     date.GetYear(wxDateTime::UTC) % date.GetHour(wxDateTime::UTC) % date.GetMinute(wxDateTime::UTC) % date.GetSecond(wxDateTime::UTC);
    return temp;
}

wxThread::ExitCode CHTTPDownloadThread::Entry()
{
	if (TestDestroy()) {
		return nullptr;
	}

	wxHTTP* url_handler = nullptr;

	//AddDebugLogLineN(logHTTP, wxT("HTTP download thread started"));

	bool use_proxy = false;

	try {
		wxFFileOutputStream outfile(m_temp_file);

		if (!outfile.Ok()) {
			//throw wxString(CFormat(_("Unable to create destination file %s for download!")) % m_temp_file);
		}

		if (m_url.IsEmpty()) {
			// Nowhere to download from!
			throw wxString(_("The URL to download can't be empty"));
		}
        //
		url_handler = new wxHTTP;
		url_handler->SetProxyMode(use_proxy);

		// Build a conditional get request if the last modified date of the file being updated is known
		if (m_last_modified.IsValid()) {
			// Set a flag in the HTTP header that we only download if the file is newer.
			// see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
			//AddDebugLogLineN(logHTTP, wxT("If-Modified-Since: ") + FormatDateHTTP(m_last_modified));
			url_handler->SetHeader(wxT("If-Modified-Since"), FormatDateHTTP(m_last_modified));
		}
        //
		wxInputStream* url_read_stream = (GetInputStream(url_handler, m_url, use_proxy));

		if (url_read_stream!= nullptr) {
			if (m_response == 304) {
				m_result = HTTP_Skipped;
				//AddDebugLogLineN(logHTTP, wxT("Skipped download because requested file is not newer."));
				throw wxString(wxEmptyString);
			} else {
				m_result = HTTP_Error;
				//throw wxString(CFormat(_("The URL %s returned: %i - Error (%i)!")) % m_url % m_response % m_error);
			}
		}

		int download_size = url_read_stream->GetSize();
#ifdef __DEBUG__
		if (download_size == -1) {
			AddDebugLogLineN(logHTTP, wxT("Download size not received, downloading until connection is closed"));
		} else {
			AddDebugLogLineN(logHTTP, CFormat(wxT("Download size: %i")) % download_size);
		}
#endif

		// Here is our read buffer
		// <ken> Still, I'm sure 4092 is probably a better size.
		// MP: Most people can download at least at 32kb/s from http...
		const unsigned MAX_HTTP_READ = 32768;

		char buffer[MAX_HTTP_READ];
		int current_read = 0;
		int total_read = 0;
		do {
			url_read_stream->Read(buffer, MAX_HTTP_READ);
			//
			current_read = url_read_stream->LastRead();
			if (current_read) {
				total_read += current_read;
				outfile.Write(buffer,current_read);
				int current_write = outfile.LastWrite();
				if (current_read != current_write) {
					throw wxString(_("Critical error while writing downloaded file"));
				} else if (m_companion) {

				}
			}
		} while (current_read && !TestDestroy());

		if (current_read == 0) {
			if (download_size == -1) {
				// Download was probably successful.
				//AddLogLineN(CFormat(_("Downloaded %d bytes")) % total_read);
				m_result = HTTP_Success;
			} else if (total_read != download_size) {
				m_result = HTTP_Error;
				//throw wxString(CFormat(_("Expected %d bytes, but downloaded %d bytes")) % download_size % total_read);
			} else {
				// Download was successful.
				m_result = HTTP_Success;
			}
		}
	} catch (const wxString& error) {
		if (wxFileExists(m_temp_file)) {
			wxRemoveFile(m_temp_file);
		}
		if (!error.IsEmpty()) {
			//AddLogLineC(error);
		}
	}

	if (m_result == HTTP_Success) {
		//thePrefs::SetLastHTTPDownloadURL(m_file_id, m_url);
	}

	if (url_handler) {
		url_handler->Destroy();
	}

	//AddDebugLogLineN(logHTTP, wxT("HTTP download thread ended"));

	return nullptr;
}


void CHTTPDownloadThread::OnExit()
{

	if (m_companion) {
		//CMuleInternalEvent termEvent(wxEVT_HTTP_SHUTDOWN);
		//wxPostEvent(m_companion, termEvent);
	}

	// Notice the app that the file finished download
	//CMuleInternalEvent evt(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD);
	//evt.SetInt((int)m_file_id);
	//evt.SetExtraLong((long)m_result);
	//
	/*
	wxPostEvent(wxTheApp, evt);
	wxMutexLocker lock(s_allThreadsMutex);
	s_allThreads.erase(this);
	 */
}


//! This function's purpose is to handle redirections in a proper way.
wxInputStream* CHTTPDownloadThread::GetInputStream(wxHTTP * & url_handler, const wxString& location, bool proxy)
{
	// Extract the protocol name
	wxString protocol(location.BeforeFirst(wxT(':')));

	if (TestDestroy()) {
		return nullptr;
	}

	if (protocol != wxT("http")) {
		// This is not a http url
		//throw wxString(CFormat(_("Protocol not supported for HTTP download: %s")) % protocol);
	}

	// Get the host

	// Remove the "http://"
	wxString host = location.Right(location.Len() - 7); // strlen("http://") -> 7

	// I believe this is a bug...
	// Sometimes "Location" header looks like this:
	// "http://www.whatever.com:8080http://www.whatever.com/downloads/something.zip"
	// So let's clean it...

	int bad_url_pos = host.Find(wxT("http://"));
	wxString location_url;
	if (bad_url_pos != -1) {
		// Malformed Location field on header (bug above?)
		location_url = host.Mid(bad_url_pos);
		host = host.Left(bad_url_pos);
		// After the first '/' non-http-related, it's the location part of the URL
		location_url = location_url.Right(location_url.Len() - 7).AfterFirst(wxT('/'));
	} else {
		// Regular Location field
		// After the first '/', it's the location part of the URL
		location_url = host.AfterFirst(wxT('/'));
		// The host is everything till the first "/"
		host = host.BeforeFirst(wxT('/'));
	}

	// Build the cleaned url now
	wxString url = wxT("http://") + host + wxT("/") + location_url;

	int port = 80;
	if (host.Find(wxT(':')) != -1) {
		// This http url has a port
		port = wxAtoi(host.AfterFirst(wxT(':')));
		host = host.BeforeFirst(wxT(':'));
	}

	wxIPV4address addr;
	addr.Hostname(host);
	addr.Service(port);
	//
	if (!url_handler->Connect(addr, true)) {
		throw wxString(_("Unable to connect to HTTP download server"));
	}

	wxInputStream* url_read_stream = url_handler->GetInputStream(url);
    //wxInputStream* url_read_stream = url_handler->GetInputStream(location_url);

	if( url_read_stream== nullptr ){
	    //!!, fail

	}
	/* store the HTTP response code
	 * 400 Bad Request
	 * 403  资源不可用
	 * */
	m_response = url_handler->GetResponse();

	/* store the HTTP error code */
	m_error = url_handler->GetError();

	if( m_error== wxProtocolError::wxPROTO_NOFILE ){
	    //!
//        AddDebugLogLineN(logHTTP, CFormat(wxT("Response: %i (Error: %i)")) % m_response % m_error);
	}
/*
	AddDebugLogLineN(logHTTP, CFormat(wxT("Host: %s:%i\n")) % host % port);
	AddDebugLogLineN(logHTTP, CFormat(wxT("URL: %s\n")) % url);
	AddDebugLogLineN(logHTTP, CFormat(wxT("Response: %i (Error: %i)")) % m_response % m_error);
*/
	if (!m_response) {
		//AddDebugLogLineC(logHTTP, wxT("WARNING: Void response on stream creation"));
		// WTF? Why does this happen?
		// This is probably produced by an already existing connection, because
		// the input stream is created nevertheless. However, data is not the same.
		delete url_read_stream;
		throw wxString(_("Invalid response from HTTP download server"));
	}

	if (m_response == 301  // Moved permanently
		|| m_response == 302 // Moved temporarily
		// What about 300 (multiple choices)? Do we have to handle it?
		) {

		// We have to remove the current stream.
		delete url_read_stream;

		wxString new_location = url_handler->GetHeader(wxT("Location"));
		//AddDebugLogLineN(logHTTP, CFormat(wxT("Redirecting to: %s")) % new_location);

		url_handler->Destroy();
		if (!new_location.IsEmpty()) {
			url_handler = new wxHTTP;
			url_handler->SetProxyMode(proxy);
			if (m_last_modified.IsValid()) {
				// Set a flag in the HTTP header that we only download if the file is newer.
				// see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
				url_handler->SetHeader(wxT("If-Modified-Since"), FormatDateHTTP(m_last_modified));
			}
			url_read_stream = GetInputStream(url_handler, new_location, proxy);
		} else {
			//AddDebugLogLineC(logHTTP, wxT("ERROR: Redirection code received with no URL"));
			url_handler = nullptr;
			url_read_stream = nullptr;
		}
	} else if (m_response == 304) {		// "Not Modified"
		delete url_read_stream;
		url_handler->Destroy();
		url_read_stream = nullptr;
		url_handler = nullptr;
	}

	return url_read_stream;
}

void CHTTPDownloadThread::StopAll()
{
	ThreadSet allThreads;
	{
		wxMutexLocker lock(s_allThreadsMutex);
		std::swap(allThreads, s_allThreads);
	}
	for (auto allThread : allThreads) {
		//allThread->Stop();
	}
}

//CHTTPDownloadThread::ThreadSet CHTTPDownloadThread::s_allThreads;
//wxMutex CHTTPDownloadThread::s_allThreadsMutex;

/*
 * showDialog
 * prepare
 * 拾取信息
 */
void showDialog(){

}

// File_checked_for_headers
//dialog handler
//connect the event to the handler
//set event id
//如何构建dialog，如同将此dialog作为消息的目标
//PreferenceFrame, list on click
//some view and connect a callback function to it
//id
//menu: Bind(wxEVT_MENU, &PreferencesFrame::OnHello, this, ID_Hello);
//close: Bind(wxEVT_CLOSE_WINDOW,wxCloseEventHandler(PreferencesFrame::OnClose),this);
//how to create a list
//on dialog button cancel
//void UpdateGauge(int total, int current)
//CHTTPDownloadDialog
//bind the percent message to the CHTTPDownloadDialog
DownloadAction::DownloadAction(MyTagApp *myTagApp, wxWindow *parent1, const wxString &name1,
                               const wxString& _url, const wxString& _save_path )
    : NormalAction(myTagApp, parent1, name1) {
    this->url = _url;
    this->save_path = _save_path;
}

//
void DownloadAction::buildDialog(){

}

//dialog与后台处理的线程需要是两个线程
//无法将action交给线程处理
//只是把dialog作为一个过程
bool DownloadAction::Prepare() {
    //show dialog, thread
    //percent
    //buildDialog();
    //bind the message
    //
    return true;
}

bool DownloadAction::Perform() {
    /*
     * while(true){
     * percent
    }
     event message to the dialog
     */
    downloadProcedure();
    return true;
}

/*
 * 线程模型
 *
 * */
int DownloadAction::downloadProcedure(  ) {
    wxHTTP *url_handler = nullptr;

    //AddDebugLogLineN(logHTTP, wxT("HTTP download thread started"));

    bool use_proxy = false;

    try {
        wxFFileOutputStream outfile(save_path);

        if (!outfile.Ok()) {
            //throw wxString(CFormat(_("Unable to create destination file %s for download!")) % m_temp_file);
        }

        if (url.IsEmpty()) {
            // Nowhere to download from!
            throw wxString(_("The URL to download can't be empty"));
        }
        //
        url_handler = new wxHTTP;
        url_handler->SetProxyMode(use_proxy);

        // Build a conditional get request if the last modified date of the file being updated is known
        /*
        if (m_last_modified.IsValid()) {
            // Set a flag in the HTTP header that we only download if the file is newer.
            // see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
            //AddDebugLogLineN(logHTTP, wxT("If-Modified-Since: ") + FormatDateHTTP(m_last_modified));
            url_handler->SetHeader(wxT("If-Modified-Since"), FormatDateHTTP(m_last_modified));
        }*/
        //
        wxInputStream *url_read_stream = (GetInputStream(url_handler, url, use_proxy));

        if (url_read_stream != nullptr) {
            if (m_response == 304) {
                m_result = HTTP_Skipped;
                //AddDebugLogLineN(logHTTP, wxT("Skipped download because requested file is not newer."));
                throw wxString(wxEmptyString);
            } else {
                m_result = HTTP_Error;
                //throw wxString(CFormat(_("The URL %s returned: %i - Error (%i)!")) % m_url % m_response % m_error);
            }
        }

        int download_size = url_read_stream->GetSize();
#ifdef __DEBUG__
        if (download_size == -1) {
            AddDebugLogLineN(logHTTP, wxT("Download size not received, downloading until connection is closed"));
        } else {
            AddDebugLogLineN(logHTTP, CFormat(wxT("Download size: %i")) % download_size);
        }
#endif

        // Here is our read buffer
        // <ken> Still, I'm sure 4092 is probably a better size.
        // MP: Most people can download at least at 32kb/s from http...
        const unsigned MAX_HTTP_READ = 32768;

        char buffer[MAX_HTTP_READ];
        int current_read = 0;
        int total_read = 0;
        do {
            url_read_stream->Read(buffer, MAX_HTTP_READ);
            //
            current_read = url_read_stream->LastRead();
            if (current_read) {
                total_read += current_read;
                outfile.Write(buffer, current_read);
                int current_write = outfile.LastWrite();
                if (current_read != current_write) {
                    throw wxString(_("Critical error while writing downloaded file"));
                }
                //percent

            }
        } while (current_read );

        if (current_read == 0) {
            if (download_size == -1) {
                // Download was probably successful.
                //AddLogLineN(CFormat(_("Downloaded %d bytes")) % total_read);
                m_result = HTTP_Success;
            } else if (total_read != download_size) {
                m_result = HTTP_Error;
                //throw wxString(CFormat(_("Expected %d bytes, but downloaded %d bytes")) % download_size % total_read);
            } else {
                // Download was successful.
                m_result = HTTP_Success;
            }
        }
    } catch (const wxString &error) {
        if (!error.IsEmpty()) {
            //AddLogLineC(error);
        }
    }

    if (m_result == HTTP_Success) {
        //thePrefs::SetLastHTTPDownloadURL(m_file_id, m_url);
    }

    if (url_handler) {
        url_handler->Destroy();
    }
}

/**
 * wxCurl
 * Boost的asio
 * 使用wxHTTP下载文件？
 * http://cn.voidcc.com/question/p-oukolxdp-hw.html
 */
wxInputStream *DownloadAction::GetInputStream(wxHTTP *pHttp, const wxString &location, bool proxy) {
    // Extract the protocol name
    wxString protocol(location.BeforeFirst(wxT(':')));

    if (protocol != wxT("http")) {
        // This is not a http url
        //throw wxString(CFormat(_("Protocol not supported for HTTP download: %s")) % protocol);
    }

    // Get the host

    // Remove the "http://"
    wxString host = location.Right(location.Len() - 7); // strlen("http://") -> 7

    // I believe this is a bug...
    // Sometimes "Location" header looks like this:
    // "http://www.whatever.com:8080http://www.whatever.com/downloads/something.zip"
    // So let's clean it...

    int bad_url_pos = host.Find(wxT("http://"));
    wxString location_url;
    if (bad_url_pos != -1) {
        // Malformed Location field on header (bug above?)
        location_url = host.Mid(bad_url_pos);
        host = host.Left(bad_url_pos);
        // After the first '/' non-http-related, it's the location part of the URL
        location_url = location_url.Right(location_url.Len() - 7).AfterFirst(wxT('/'));
    } else {
        // Regular Location field
        // After the first '/', it's the location part of the URL
        location_url = host.AfterFirst(wxT('/'));
        // The host is everything till the first "/"
        host = host.BeforeFirst(wxT('/'));
    }

    // Build the cleaned url now
    wxString url = wxT("http://") + host + wxT("/") + location_url;

    int port = 80;
    if (host.Find(wxT(':')) != -1) {
        // This http url has a port
        port = wxAtoi(host.AfterFirst(wxT(':')));
        host = host.BeforeFirst(wxT(':'));
    }

    wxIPV4address addr;
    addr.Hostname(host);
    addr.Service(port);
    //
    if (!pHttp->Connect(addr, true)) {
        throw wxString(_("Unable to connect to HTTP download server"));
    }

    //
    wxInputStream* url_read_stream = pHttp->GetInputStream(url);
    //wxInputStream* url_read_stream = url_handler->GetInputStream(location_url);

    if( url_read_stream== nullptr ){
        //!!, fail

    }
    /* store the HTTP response code
     * 400 Bad Request
     * 403  资源不可用
     * */
    m_response = pHttp->GetResponse();

    /* store the HTTP error code */
    m_error = pHttp->GetError();

    if( m_error== wxProtocolError::wxPROTO_NOFILE ){
        //!
//        AddDebugLogLineN(logHTTP, CFormat(wxT("Response: %i (Error: %i)")) % m_response % m_error);
    }
/*
AddDebugLogLineN(logHTTP, CFormat(wxT("Host: %s:%i\n")) % host % port);
AddDebugLogLineN(logHTTP, CFormat(wxT("URL: %s\n")) % url);
AddDebugLogLineN(logHTTP, CFormat(wxT("Response: %i (Error: %i)")) % m_response % m_error);
*/
    if (!m_response) {
        //AddDebugLogLineC(logHTTP, wxT("WARNING: Void response on stream creation"));
        // WTF? Why does this happen?
        // This is probably produced by an already existing connection, because
        // the input stream is created nevertheless. However, data is not the same.
        delete url_read_stream;
        throw wxString(_("Invalid response from HTTP download server"));
    }
    //relocate
    if (m_response == 301  // Moved permanently
        || m_response == 302 // Moved temporarily
        // What about 300 (multiple choices)? Do we have to handle it?
            ) {

        // We have to remove the current stream.
        delete url_read_stream;
        //ignore
    } else if (m_response == 304) {		// "Not Modified"
        delete url_read_stream;
        pHttp->Destroy();
        url_read_stream = nullptr;
        pHttp = nullptr;
    }

    return url_read_stream;
}

void DownloadAction::DownloadIt(const wxString &url, const wxString &save_path) {

}
